#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44

int lastcode = 0;
int quit = 0;
extern char **environ;
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];
char pwd[LINE_SIZE];

//自定义环境变量
char myenv[LINE_SIZE];

const char *getusername(){
    return getenv("USER");
}

const char *gethostname(){
    return getenv("HOSTNAME");
}

void getpwd(){
    getcwd(pwd,sizeof(pwd));
}

void Interact(char *cline, int size){
    getpwd();
    printf(LEFT"%s@%s %s"RIGHT""LABLE" ",getusername(),gethostname(),pwd);
    char *s = fgets(cline, size, stdin);
    assert(s);
    (void)s;
    
    cline[strlen(cline)-1] = '\0';
}

int splistring(char cline[], char *_argv[]){
    int i = 0;
    argv[i++] = strtok(cline, DELIM);
    while(_argv[i++] = strtok(NULL, DELIM));
    return i-1;
}
	
void NormalExcute(char *_argv[]){
    pid_t id = fork();
        if(id < 0){
            perror("fork");
            return;
        }
        else if(id == 0){
            //让子进程执行命令
            execvp(_argv[0], _argv);
            exit(EXIT_CODE);
        }
        else{
            int status = 0;
            pid_t rid = waitpid(id, &status, 0);
            if(rid == id){
                lastcode = WEXITSTATUS(status);
            }
        }
}

int buildCommand(char *_argv[],int _argc){
    if(_argc == 2 && strcmp(_argv[0],"cd")==0){
            chdir(argv[1]);
            getpwd();
            sprintf(getenv("PWD"),"%s", pwd);
            return 1;
    }
    else if(_argc == 2 && strcmp(_argv[0],"export")==0){
        strcpy(myenv, _argv[1]);
		putenv(myenv);
        return 1;
    }
    else if(_argc == 2 && strcmp(_argv[0],"echo")==0){
        if(strcmp(_argv[1],"$?")==0){
            printf("%d\n",lastcode);
            lastcode=0;
        }
        else if(*_argv[1]=='$'){
            char *val = getenv(_argv[1]+1);
            if(val) printf("%s\n",val);
        }
        else{
            printf("%s\n",_argv[1]);
        }
        return 1;
    }
    
    //特殊处理一下ls
    if(strcmp(_argv[0],"ls")==0){
        _argv[_argc++] = "--color";
        _argv[_argc] = NULL;
    }
    
    return 0;
}

int main(){
    while(!quit){
		//1.
        //2.交互问题，获取命令行
        Interact(commandline, sizeof(commandline));
        //3.子串分割的问题，解析命令行
        int argc = splistring(commandline, argv);
        if(argc == 0) continue;
        
        //4.指令的判断,判断是不是内嵌命令
        //debug
        //for(int i=0;argv[i];i++){
        //    printf("[%d]: %s\n",i,argv[i]);
        //}
        //内键命令本质上就是shell内部的一个函数。
        int n = buildCommand(argv, argc);
        
        
        //5.普通命令的执行
        if(!n) NormalExcute(argv);
    }
    return 0;
}
